'use strict'
//函数是一等公民，函数是最基本的一种代码抽象方式
//函数定义和调用
//函数的第一种定义方式
function abs(x) {
  if (x > 0) {
    return x;
  } else {
    return -x;
  }
}

//函数也是一个对象 函数名abs可以视为指向该函数的变量
//因此 函数的第二种定义方式如下图所示
var abs = function (x) {
  if (x > 0) {
    return x;
  } else {
    return -x;
  }
};
//上述是匿名函数 注意定义的时候需要加上;
//调用函数，按顺序传递参数即可，JavaScript允许传入任意个参数而不影响调用，传入多传入少都没啥影响

console.log(abs(-9, 'haha', 'hehe', null));
console.log(abs()); //函数的参数X将接受undefined，返回的结果NaN

//避免参数受到undefined，可以做一个参数检查
function abs(x) {
  if(typeof x!=Number){
    throw 'Not a number'
  }
  if (x > 0) {
    return x;
  } else {
    return -x;
  }
}

//arguments关键字，就当作一个包含所有参数的array
//arguments关键字只在函数内部起作用，并且永远指向当前函数的调用者传入的所有参数，类似于Array但不是一个Array
//常用来判断参数个数
//arguments.callee 指向当前执行的函数
//arguments.caller 指向调用当前函数的函数
//arguments.length 指向传递给当前函数的参数数量
//arguments[@@iterator] 返回一个新的Array迭代器对象，该对象包含参数中每个索引的值
function foo(x){
        console.log('x='+x);
  for(var i=0;i<arguments.length;i++){
    console.log('arg'+i+'='+arguments[i]);
  }

}
foo(10,20,30);

//即使不定义任何参数，argument也能拿到参数值
function foo2(){
for(var i=0;i<arguments.length;i++){
  console.log(arguments[i])
}
}
foo2(100,99,98,97)

//debugger;//可以用来打断点

//rest参数
//js语法允许向一个函数传递超过数量的参数,为了获取定义的自定参数以外的参数，ES6支持rest参数
//如果想要获得自定义参数以外的参数可以类似于下面的写法
//ES5写法如下
function foo(a, b) {
  var i, rest = [];
  if (arguments.length > 2) {
      for (i = 2; i<arguments.length; i++) {
          rest.push(arguments[i]);
      }
  }
  console.log('a = ' + a);
  console.log('b = ' + b);
  console.log(rest);
}

//ES6引入了rest参数能方便获得自定义下的剩余参数
function foo3(a,b,...rest){
  console.log(a);
  console.log(b);
  console.log(rest);
}
foo3(1,2,3,4,5);
foo3(1)
//如果传入的参数连正常定义的参数都没填满，也不要紧，rest参数会接收一个空数组 注意不是undefined
